<!-- Created by henian.xu on 2018/8/2. -->

<template>
    <el-cascader
        :filterable="filterable"
        :props="props"
        :options="options"
        :change-on-select="changeOnSelect"
        @change="onItemChange"
        @active-item-change="onItemChange"
        v-model="model"
    />
</template>

<script>
export default {
    name: 'CascaderPicker',
    data() {
        return {
            options: [],
            optionsMap: {},
            props: {
                value: 'id',
                label: 'name',
                children: 'children',
                disabled: 'disabled',
            },
            innerCtrl: false,
            cancelSource: null,
        };
    },
    props: {
        value: {
            type: [Number, String],
            default: '',
        },
        /**
         * api 类，必需实现 select方法
         */
        apiClass: {
            type: Object,
            default: null,
        },
        selectApi: {
            type: String,
            default: '',
        },
        loadSelectNodeApi: {
            type: String,
            default: '',
        },
        minLv: {
            type: Number,
            default: 1,
        },
        pId: {
            type: Number,
            default: 0,
        },
        changeOnSelect: {
            type: Boolean,
            default: false,
        },
        filterable: {
            type: Boolean,
            default: false,
        },
    },
    computed: {
        model: {
            get() {
                const { value, optionsMap } = this;
                const item = optionsMap[value];
                if (!item) return [];
                return this.splicePath(item.idPath);
            },
            set(val) {
                const id = val[val.length - 1];
                this.$emit('input', id + '');
                this.innerCtrl = true;
            },
        },
        apiSelect() {
            const { selectApi, apiClass } = this;
            if (apiClass) {
                return data => {
                    return apiClass.select(data);
                };
            } else {
                return data => {
                    return this.$http.get(selectApi, data);
                };
            }
        },
        apiLoadSelectNode() {
            const { loadSelectNodeApi, apiClass } = this;
            if (apiClass) {
                return data => {
                    return apiClass.loadSelectNode(data);
                };
            } else {
                return data => {
                    return this.$http.get(loadSelectNodeApi, data);
                };
            }
        },
    },
    watch: {
        value: {
            handler(val) {
                // if (!val) return;
                if (this.innerCtrl) {
                    this.innerCtrl = false;
                    return;
                }
                if (val) {
                    this.cancelSource && this.cancelSource.cancel({ msg: '取消子查询' });
                    this.getLoadSelectNode({ id: val }).then(json => {
                        const res = json.data;
                        this.options = this.$utils.Convert.listToTree(res.data, this.lv);
                    });
                } else {
                    this.cancelSource = this.$http.createCancelToken();
                    this.getChildren({ pId: this.pId, _cancelSource: this.cancelSource }).then(json => {
                        const res = json.data;
                        this.options = res.data;
                    });
                }
            },
            immediate: true,
        },
    },
    methods: {
        // 可以合并到 Convert.listToTree 方法里
        buildData(data) {
            data.forEach(item => {
                item.id += '';
                item.children = item.children || item.isLeaf ? null : [];
                item._loaded = item.isLeaf || (!!item.children && !!item.children.length);
                this.$set(this.optionsMap, item.id, item);
            });
        },
        getChildren(data) {
            return this.apiSelect(data).then(json => {
                this.buildData(json.data.data);
                this.$utils.Convert.sortAtOrderNum(json.data.data);
                return Promise.resolve(json);
            });
        },
        getLoadSelectNode(data) {
            return this.apiLoadSelectNode(data).then(json => {
                this.buildData(json.data.data);
                return Promise.resolve(json);
            });
        },
        onItemChange(val) {
            const id = val[val.length - 1];
            const item = this.optionsMap[id];
            if (!item || item._loaded) return;
            this.getChildren({ pId: id }).then(json => {
                const res = json.data;
                item._loaded = true;
                item.children = res.data;
            });
        },
        splicePath(data, separator = '>') {
            const reg = new RegExp('(^' + separator + '*)|(' + separator + '*$)', 'g');
            data = data.replace(reg, '');
            const arr = data.split(separator);
            return arr.splice(this.minLv - 1, arr.length);
        },
    },
};
</script>

<style lang="scss">
</style>
